﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace ExpressionEvaluation
{
    public class ExpressionEvaluator
    {
        private const string codeFormat =
        @"using System;
namespace ExpressionEvaluation
{
public class EvaluatorHelper
{
public double Evaluate()
{
return {0};
}
}
}";
        private CSharpCodeProvider cSharpCodeProvider;
        private string PrepareExpression(string expression)
        {
            StringBuilder expressionBuilder = new StringBuilder(expression);
            expressionBuilder.Replace("sqrt", "Math.Sqrt");
            expressionBuilder.Replace("ln", "Math.Log");
            expressionBuilder.Replace("pow", "Math.Pow");
            //return string.Format(codeFormat, expressionBuilder.ToString());
            return codeFormat.Replace("{0}", expressionBuilder.ToString());
        }
        public ExpressionEvaluator()
        {
            cSharpCodeProvider = new CSharpCodeProvider();
        }
        public double Evaluate(string expression)
        {
            expression = this.PrepareExpression(expression);
            CompilerParameters cp = new CompilerParameters();
            cp.ReferencedAssemblies.Add("system.dll");
            cp.GenerateInMemory = true;
            CompilerResults cr = cSharpCodeProvider.CompileAssemblyFromSource(cp, expression);
            System.Reflection.Assembly a = cr.CompiledAssembly;
            object obj = a.CreateInstance("ExpressionEvaluation.EvaluatorHelper");
            object invokeResult = obj.GetType().GetMethod("Evaluate").Invoke(obj, null);
            double result = 0;
            double.TryParse(invokeResult.ToString(), out result);
            return result;
        }
    }
}
